/**
 * 
 */
package decoder;

import structure.Line;
import structure.PICStack;
import gui.control.Pic;
import structure.Register;
import structure.WRegister;
import structure.Byte;

/**
 * Diese Klasse bildet die Befehle des PIC 16 Microcontrollers nach.
 * @author Dorothee Kern und Patrick Lehmann
 *
 */
public class Commands {

    private static Commands instance = null;

    private Commands() {
    }

    ;

    /**
     * 	Singleton Pattern.
     *
     * @return Eine Instanz von Commands
     */
    public static Commands getInstance() {
        if (instance == null) {
            instance = new Commands();
        }
        return instance;
    }

    /**
     * Addiert 8 Bit-Konstante zu W-Register und speichert Ergebnis in W-Register.
     * @param line Befehlszeile
     */
    public void comADDLW(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        //W + 8 Bit Konstante
        int w = WRegister.getInstance().getWRegAsInt();
        int l = line.getArg8Bit();
        int result = w + l;
        //Pruefen, ob Flags gesetzt werden m�ssen
        checkDigitCarry(w, l);
        result = checkCarry(result);
        checkZero(result);
        //Ergebnis in W speichern
        WRegister.getInstance().setWReg(result);
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Addiert 7-Bit Zahl aus File Register mit W-Register. Bit 7 gibt Speicherort
     * fuer Ergebnis an. Bei 0 in W-Register, bei 1 in File-Register.
     * @param line Befehlszeile
     */
    public void comADDWF(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        int address = line.getArg7Bit();
        int w = WRegister.getInstance().getWRegAsInt();
        int f = Register.getInstance().getRegisterByteAsInt(address);
        //W + 7 Bit File Register
        int result = w + f;
        //Pruefen, ob Flags gesetzt werden m�ssen
        checkDigitCarry(w, f);
        result = checkCarry(result);
        checkZero(result);
        //Speicherort waehlen
        checkDestination(result, line);
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Bitweises UND mit W-Register und 8-Bit Konstante
     * @param line Befehlszeile
     */
    public void comANDLW(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        int w = WRegister.getInstance().getWRegAsInt();
        int l = line.getArg8Bit();
        //Bitweise verunden der Werte w und l
        int result = w & l;
        //Pruefen, ob Flags gesetzt werden m�ssen
        checkZero(result);
        WRegister.getInstance().setWReg(result);
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Bitweises UND mit W-Register und File-Register.
     * @param line Befehlszeile
     */
    public void comANDWF(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        int address = line.getArg7Bit();
        int w = WRegister.getInstance().getWRegAsInt();
        int f = Register.getInstance().getRegisterByteAsInt(address);
        //Bitweise verunden der Werte w und f
        int result = w & f;
        //Pr�fen, ob Flags gesetzt werden m�ssen
        checkZero(result);
        //Speicherort waehlen
        checkDestination(result, line);
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Loeschen eines Bit im File-Register.
     * @param line Befehlszeile
     */
    public void comBCF(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        //Maskieren des 11bit Argumentes um nur die Bits 7 bis 9 zu speichern.
        //Teilen durch 32 um die Bits 7 bis 9 auf bit 0 - 2 darzustellen.
        int bit = (line.getArg11Bit() & 0x380) >>> 7;
        int address = line.getArg7Bit();
        //setzen des Bit auf false -> somit clear
        Register.getInstance().setRegisterBit(address, bit, false);
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Setzen eines Bit im File-Register.
     * @param line Befehlszeile
     */
    public void comBSF(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        //Maskieren des 11bit Argumentes um nur die Bits 7 bis 9 zu speichern.
        //Teilen durch 32 um die Bits 7 bis 9 auf bit 0 - 2 darzustellen.
        int bit = (line.getArg11Bit() & 0x380) >>> 7;
        int address = line.getArg7Bit();
        //setzen des Bit auf true -> somit gesetzt
        Register.getInstance().setRegisterBit(address, bit, true);
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Pruefen ob ein Bit clear ist. Wenn Bit Clear, dann
     * naechsten Befehl ueberspringen, sonst naechster Befehl.
     * @param line Befehlszeile
     */
    public void comBTFSC(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        //Maskieren des 11bit Argumentes um nur die Bits 7 bis 9 zu speichern.
        //Teilen durch 32 um die Bits 7 bis 9 auf bit 0 - 2 darzustellen.
        int bit = (line.getArg11Bit() & 0x380) >>> 7;
        int address = line.getArg7Bit();
        //pruefen des Bit
        boolean value = Register.getInstance().getRegisterBit(address, bit);
        if (value == false) {
            Register.getInstance().incProgramCounter();
            //1 Maschinenzyklus
            Pic.getInstance().incTime();
        }
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();

    }

    /**
     * Pruefen ob ein Bit gesetzt ist. Wenn Bit gesetzt, dann
     * naechsten Befehl ueberspringen, sonst naechster Befehl.
     * @param line Befehlszeile
     */
    public void comBTFSS(Line line) {
        //PC erhoehen
        Register.getInstance().incProgramCounter();
        //Maskieren des 11bit Argumentes um nur die Bits 7 bis 9 zu speichern.
        //7Stellen nach rechts schieben, um die Bits 9 bis 7 auf bit 0 - 2 darzustellen.
        int bit = (line.getArg11Bit() & 0x380) >>> 7;
        int address = line.getArg7Bit();
        //pruefen des Bit
        boolean value = Register.getInstance().getRegisterBit(address, bit);
        if (value == true) {
            Register.getInstance().incProgramCounter();
            //1 Maschinenzyklus
            Pic.getInstance().incTime();
        }
        //1 Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();

    }

    /**
     * Ruft ein Unterprogramm auf, in dem die Sprungadresse in den
     * ProgramCounter geschrieben wird.
     * Sichert nachfolgenden ProgramCounter im Stack.
     * @param line Befehlszeile
     */
    public void comCALL(Line line) {
        Register.getInstance().incProgramCounter();
        //Ruecksprungadresse auf Stack speichern
        PICStack.getInstance().push(Register.getInstance().getProgramCounter());
        //Sprungadresse in PC speichern (k->PC)
        Register.getInstance().setProgramCounter(line.getArg11Bit());
        //(PCLATH<4:3> -> PC<12:11>)
        //pc = Letzte 11 Bit des Programmcounter
        int pc = Register.getInstance().getProgramCounter() & 0x7FF;
        int pclath = Register.getInstance().getRegisterByteAsInt(0x0A);
        //pclath maskieren um die Bits an Stelle 4 und 3 zu erhalten
        //verschieben diese Bits an die Stelle 12 und 11.
        //Addition zum bestehenden pc
        Register.getInstance().setProgramCounter((pc + (pclath & 0x18) * 0x100));
        //Zwei Maschinenzyklen
        Pic.getInstance().incTime();
        Pic.getInstance().incTime();
        ;
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Loeschen eines File-Registers.
     * @param line Befehlszeile
     */
    public void comCLRF(Line line) {
        Register.getInstance().incProgramCounter();
        Register.getInstance().setRegisterByteAsInt(line.getArg7Bit(), 0);
        //Zeroflag setzen wird durch die 0 erzwungen
        checkZero(0);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Loeschen des W-Registers.
     * @param line Befehlszeile
     */
    public void comCLRW(Line line) {
        Register.getInstance().incProgramCounter();
        WRegister.getInstance().setWReg(0);
        //Zeroflag setzen wird durch die 0 erzwungen
        checkZero(0);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Setzt den Watchdogtimer und den WDT-Prescalor zurück.
     * @param line Befehlszeile
     */
    public void comCLRWDT(Line line) {
        Register.getInstance().incProgramCounter();
        //Watchdogtimer zurücksetzen
        Pic.time = 0;
        //Prescalor zurücksetzen
        Register.getInstance().setRegisterBit(0x81, 0, false);
        Register.getInstance().setRegisterBit(0x81, 1, false);
        Register.getInstance().setRegisterBit(0x81, 2, false);
        //Statusflegs setzen nicht TO, nicht PD
        Register.getInstance().setRegisterBit(0x03, 3, true);
        Register.getInstance().setRegisterBit(0x03, 4, true);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();

    }

    /**
     * Invertiert den Inhalt eines F-Registers.
     * @param line Befehlszeile
     */
    public void comCOMF(Line line) {
        Register.getInstance().incProgramCounter();
        //Adresse einlesen und Byte als Boolean Array speichern
        boolean[] value = Register.getInstance().getRegisterByte(line.getArg7Bit()).getByteAsArray();
        //invertieren des Array
        value = complement(value);
//                for (int i = 0; i < value.length; i++) {
//			if (value[i] == true)
//				value [i] = false;
//			else
//				value [i] = true;
//
//		}
        //Ergebnis abspeichern in result Byte
        Byte result = new Byte();
        result.setByte(value);
        //ueberpruefen ob Zero Flag gesetzt werden muss
        checkZero(result.getByteAsInt());
        //Speicherort waehlen
        checkDestination(result.getByteAsInt(), line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Dekrementiert ein File-Register. Bei Unterlauf wird 255 gesetzt.
     * @param line Befehlszeile
     */
    public void comDECF(Line line) {
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit()) - 1;
        //Wenn kleiner 0 soll 255 in das Byte geschrieben werden.
        if (value < 0) {
            value = 0xFF;
        }

        //Zero Flag pruefen
        checkZero(value);
        //Speicherort waehlen
        checkDestination(value, line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Dekrementiert ein File-Register und ueberspringt die naechste Zeile,
     * wenn das Ergebnis 0 ist.
     * @param line Befehlszeile
     */
    public void comDECFSZ(Line line) {
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit()) - 1;
        //Unterlauf abfangen
        if (value < 0) {
            value = 0xFF;
        }
        //Skip if Zero
        if (value == 0) {
            Register.getInstance().incProgramCounter();
            Pic.getInstance().incTime();
        }
        //Speicherort waehlen
        checkDestination(value, line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Setzt den ProgramCounter auf die Sprungadresse.
     * @param line Befehlszeile
     */
    public void comGOTO(Line line) {
        Register.getInstance().incProgramCounter();
        //Sprungadresse in PC speichern (k->PC)
        Register.getInstance().setProgramCounter(line.getArg11Bit());
        //(PCLATH<4:3> -> PC<12:11>)
        //pc = Letzte 11 Bit des Programmcounter
        int pc = Register.getInstance().getProgramCounter() & 0x7FF;
        int pclath = Register.getInstance().getRegisterByteAsInt(0x0A);
        //pclath maskieren um die Bits an Stelle 4 und 3 zu erhalten
        //verschieben diese Bits an die Stelle 12 und 11.
        //Addition zum bestehenden pc
        Register.getInstance().setProgramCounter((pc + (pclath & 0x18) * 0x100));
        //Zwei Maschinenzyklen
        Pic.getInstance().incTime();
        Pic.getInstance().incTime();
        ;
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Inkrementiert File-Register.
     * @param line Befehlszeile
     */
    public void comINCF(Line line) {
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit()) + 1;
        //Wenn groesser 255 soll 0 in das Byte geschrieben werden.
        if (value > 0xFF) {
            value = 0;
        }
        //Zero Flag pruefen
        checkZero(value);
        //Speicherort waehlen
        checkDestination(value, line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Inkrementiert das File-Register und ueberspringt die naechste Zeile,
     * wenn das Ergebnis 0 ist.
     * @param line Befehlszeile
     */
    public void comINCFSZ(Line line) {
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit()) + 1;
        //Ueberlauf abfangen
        if (value > 0xFF) {
            value = 0;
        }
        //Skip if Zero
        if (value == 0) {
            Register.getInstance().incProgramCounter();
            Pic.getInstance().incTime();
        }
        //Speicherort waehlen
        checkDestination(value, line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Logisches inklusiv-oder mit Literal und W-Register.
     * @param line Befehlszeile
     */
    public void comIORLW(Line line) {
        Register.getInstance().incProgramCounter();
        int result = WRegister.getInstance().getWRegAsInt() | line.getArg8Bit();
        //Ergebnis in W-Register schreiben
        WRegister.getInstance().setWReg(result);
        //Zero Flag pruefen
        checkZero(result);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Logisches inklusiv-oder mit F-Register und W-Register
     * @param line Befehlszeile
     */
    public void comIORWF(Line line) {
        Register.getInstance().incProgramCounter();
        int result = WRegister.getInstance().getWRegAsInt() | Register.getInstance().getRegisterByteAsInt(line.getArg7Bit());
        //Speicherort waehlen
        checkDestination(result, line);
        //Zero Flag pruefen
        checkZero(result);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Wert von F-Register entweder in W-Register oder zurueck ins F-Register speichern.
     * @param line Befehlszeile
     */
    public void comMOVF(Line line) {
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit());
        //Speicherort waehlen
        checkDestination(value, line);
        //Zero Flag pruefen
        checkZero(value);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Wert eines Literals in W-Register speichern.
     * @param line Befehlszeile
     */
    public void comMOVLW(Line line) {
        Register.getInstance().incProgramCounter();
        WRegister.getInstance().setWReg(line.getArg8Bit());
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Speichert Wert aus W-Register in F-Register.
     * @param line Befehlszeile
     */
    public void comMOVWF(Line line) {
        Register.getInstance().incProgramCounter();
        int value = WRegister.getInstance().getWRegAsInt();
        Register.getInstance().setRegisterByteAsInt(line.getArg7Bit(), value);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * No Operation.
     * @param line Befehlszeile
     */
    public void comNOP(Line line) {
        Register.getInstance().incProgramCounter();
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Return from Interrupt.
     * Schreibt den TOS in den PC und setzt das Global Interrupt Enable Bit.
     * @param line Befehlszeile
     */
    public void comRETFIE(Line line) {
        //TOS in den PC schreiben
        Register.getInstance().setProgramCounter(PICStack.getInstance().pop());
        //GIE Bit setzen
        Register.getInstance().setRegisterBit(0x0B, 7, true);
        //Zwei Maschinenzyklen
        Pic.getInstance().incTime();
        Pic.getInstance().incTime();
        ;
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();

    }

    /**
     * Return aus Unterprogramm mit Rueckgabewert.
     * @param line Befehlszeile
     */
    public void comRETLW(Line line) {
        Register.getInstance().incProgramCounter();
        WRegister.getInstance().setWReg(line.getArg8Bit());
        //ProgrammCounter mit Top of Stack ueberschreiben
        Register.getInstance().setProgramCounter(PICStack.getInstance().pop());
        //Zwei Maschinenzyklen
        Pic.getInstance().incTime();
        Pic.getInstance().incTime();
        ;
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Return aus Unterprogramm.
     * @param line Befehlszeile
     */
    public void comRETURN(Line line) {
        //Register.getInstance().incProgramCounter();
        //ProgrammCounter mit Top of Stack ueberschreiben
        Register.getInstance().setProgramCounter(PICStack.getInstance().pop());
        //Zwei Maschinenzyklen
        Pic.getInstance().incTime();
        Pic.getInstance().incTime();
        ;
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Rotiert File-Register nach Links, MSB wird in Carry gespeichert.
     * @param line Befehlszeile
     */
    public void comRLF(Line line) {
        int result;
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit());
        //Carry sichern
        boolean carry = Register.getInstance().getCarry();
        //Pruefen ob MSB = 1
        if (Integer.highestOneBit(value) == 7) {
            Register.getInstance().setCarry();
        } else {
            Register.getInstance().clearCarry();
        }
        //rotieren nach links
        value = value << 1;
        //alten carry an Stelle 0 setzen
        result = value & 0xfe;
        if (Register.getInstance().getCarry() == true) {
            result += 1;
        }
        //Speicherort waehlen
        checkDestination(result, line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Rotiert File-Register nach rechts, LSB wird in Carry gespeichert.
     * @param line Befehlszeile
     */
    public void comRRF(Line line) {
        int result;
        Register.getInstance().incProgramCounter();
        int value = Register.getInstance().getRegisterByteAsInt(line.getArg7Bit());
        //Carry sichern
        boolean carry = Register.getInstance().getCarry();
        //Pruefen ob LSB = 1
        if (Integer.lowestOneBit(value) == 0) {
            Register.getInstance().setCarry();
        } else {
            Register.getInstance().clearCarry();
        }
        //rotieren nach rechts
        value = value >> 1;
        //alten carry an Stelle 7 setzen
        result = value & 0x7F;
        if (Register.getInstance().getCarry() == true) {
            result += 128;
        }
        //Speicherort waehlen
        checkDestination(result, line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer prüfen
        Register.getInstance().checkWDT();
    }

    /**
     * Versetzt den Microcontroller in Ruhezustand
     * Der WDT wird zurueckgesetzt, der WDT-Prescalor wird zurueckgesetzt
     * @param line Befehlszeile
     */
    public void comSLEEP(Line line) {
        Register.getInstance().incProgramCounter();
        //Watchdogtimer zuruecksetzen
        Pic.time = 0;
        //Prescalor zuruecksetzen
        Register.getInstance().setRegisterBit(0x81, 0, false);
        Register.getInstance().setRegisterBit(0x81, 1, false);
        Register.getInstance().setRegisterBit(0x81, 2, false);
        //Statusflegs setzen nicht TO, nicht PD
        Register.getInstance().setRegisterBit(0x03, 3, false);
        Register.getInstance().setRegisterBit(0x03, 4, true);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Subtrahiert W-Register von Literal.
     * @param line Befehlszeile
     */
    public void comSUBLW(Line line) {
        int w;
        //TODO Debuggen!!!
        //Zweier-Komplement der Zahl im W-Register, maskieren um letzte 8 Bit zu erhalten
        //int w = Integer.reverse(WRegister.getInstance().getWRegAsInt()) & 0xFF;
        boolean[] value = WRegister.getInstance().getWRegAsArray();
        value = complement(value);
        Byte b = new Byte();
        b.setByte(value);
        w = b.getByteAsInt() + 1;
        //speichern des Komplements im W-Register
        WRegister.getInstance().setWReg(w);
        //Aufruf der Methode comADDLW
        comADDLW(line);
    }

    /**
     * Subtrahiert W-Register von File-Register.
     * @param line Befehlszeile
     */
    public void comSUBWF(Line line) {
        //Zweier-Komplement der Zahl im W-Register, maskieren um letzte 8 Bit zu erhalten
        int w;
        boolean[] value = WRegister.getInstance().getWRegAsArray();
        value = complement(value);
        Byte b = new Byte();
        b.setByte(value);
        w = b.getByteAsInt() + 1;
        //int w = Integer.reverse(WRegister.getInstance().getWRegAsInt()) & 0xFF;
        //speichern des Komplements im W-Register
        WRegister.getInstance().setWReg(w);
        //Aufruf der Methode comADDLW
        comADDWF(line);
    }

    /**
     * Vertauscht oberes und unteres Halbbyte eines File-Register.
     * @param line Befehlszeile
     */
    public void comSWAPF(Line line) {
        Register.getInstance().incProgramCounter();
        boolean[] value = Register.getInstance().getRegisterByte(line.getArg7Bit()).getByteAsArray();
        //Hilfsarray
        boolean[] temp = new boolean[8];
        int j = 4;
        //Werte von value[0] bis value[3] in temp[4] bis temp[7] schreiben.
        for (int i = 0; i < 4; i++) {
            temp[j] = value[i];
            j++;
        }
        j = 0;
        //Werte von value[4] bis value[7] in temp[0] bis temp[3] schreiben.
        for (int i = 4; i < 8; i++) {
            temp[j] = value[i];
            j++;
        }
        //Hilfsarray in neues Byteobjekt speichern
        Byte result = new Byte();
        result.setByte(temp);

        //Speicherort waehlen
        checkDestination(result.getByteAsInt(), line);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Exklusiv-Oder von W-Register und Literal.
     * @param line Befehlszeile
     */
    public void comXORLW(Line line) {
        Register.getInstance().incProgramCounter();
        int result = WRegister.getInstance().getWRegAsInt() ^ line.getArg8Bit();
        //Ergebnis in W-Register schreiben
        WRegister.getInstance().setWReg(result);
        //Zero Flag pruefen
        checkZero(result);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    /**
     * Exklusiv-Oder von W-Register und File-Register.
     * @param line Befehlszeile
     */
    public void comXORWF(Line line) {
        Register.getInstance().incProgramCounter();
        int result = WRegister.getInstance().getWRegAsInt() ^ Register.getInstance().getRegisterByteAsInt(line.getArg7Bit());
        //Speicherort waehlen
        checkDestination(result, line);
        //Zero Flag pruefen
        checkZero(result);
        //Ein Maschinenzyklus
        Pic.getInstance().incTime();
        //Watchdogtimer pruefen
        Register.getInstance().checkWDT();
    }

    //Helfer
    /**
     * Prueft an Hand von den beiden Summanden, ob das Digit Carry
     * bei einer Addition gesetzt werden muss.
     * @param number1 1. Summand
     * @param number2 2. Summand
     */
    public void checkDigitCarry(int number1, int number2) {
        //Digit Carry setzen, bei �berlauf der Bits 0 - 3
        if ((number1 & 0xF) + (number2 & 0xF) > 0xF) {
            Register.getInstance().setDigitCarry();
        }
    }

    /**
     * Prueft, ob Carry nach Ueberlauf gesetzt werden muss.
     * @param result Ergebnis der vorherigen Berechnung
     * @return 8-Bit Maskiertes Ergebnis
     */
    public int checkCarry(int result) {
        //Carry Flag setzen, bei Ueberlauf (>255)
        if (result > 0xFF) {
            Register.getInstance().setCarry();
            //Maskieren, um die letzen 8 Bit zu speichern.
            result = result & 0xFF;
        }
        return result;
    }

    /**
     * Prüft, ob Ergebnis 0 ist und setzt dementsprechend das Zero Flag
     * @param result Ergebnis der vorherigen Berechnung
     */
    public void checkZero(int result) {
        //Zero Flag setzen, wenn Ergebnis 0
        if (result == 0) {
            Register.getInstance().setZero();
        }
    }

    /**
     * Methode fuer 7-Bit Operationen, bei denen ein Speicherort (w-Register oder f-Register) gewaehlt werden muss.
     * @param result Ergebnis welches gespeichert werden soll
     * @param line Befehlszeile, wird ben�tigt um Speicherort zu bestimmen
     */
    public void checkDestination(int result, Line line) {
        int address = line.getArg7Bit();
        if ((line.getOpCode() & 0x80) == 0x80) {
            //in f-Register speichern
            Register.getInstance().setRegisterByteAsInt(address, result);
        } else {
            //In W-Register speichern
            WRegister.getInstance().setWReg(result);
        }
    }
    /**
     * Bildet das Komplement einer 8-Bit-Zahl.
     * @param value Zu komplementiernder Wert als Boolean Array
     * @return Komplenent von übergebenem Wert als int.
     */
    public boolean[] complement(boolean[] value) {

        for (int i = 0; i < value.length; i++) {
            if (value[i] == true) {
                value[i] = false;
            } else {
                value[i] = true;
            }

        }
        return value;
    }
}
